#!/usr/bin/env python3

"""
This is a simple program that will add Signed-off-by: tags to a range of
commits.  Example usage, to add a signed-off-by trailer to every commit that
is not in next but is in any of master, develop, or maint:
  signed-off-by master develop maint ^next
More likely called as:
  signed-off-by master~4..master
There's no real reason to use this script since `rebase --signoff` exists;
it's mostly just a demonstration of what could be done.
"""

"""
Please see the
  ***** API BACKWARD COMPATIBILITY CAVEAT *****
near the top of git-filter-repo.
"""

import argparse
import re
import subprocess
try:
  import git_filter_repo as fr
except ImportError:
  raise SystemExit("Error: Couldn't find git_filter_repo.py.  Did you forget to make a symlink to git-filter-repo named git_filter_repo.py or did you forget to put the latter in your PYTHONPATH?")

parser = argparse.ArgumentParser(
          description="Add 'Signed-off-by:' tags to a range of commits")
parser.add_argument('rev_list_args', metavar='rev-list args',
                    nargs=argparse.REMAINDER,
        help=("Range of commits (need to include ref tips) to work on"))
myargs = parser.parse_args()

user_name = subprocess.check_output('git config user.name'.split()).rstrip()
user_email = subprocess.check_output('git config user.email'.split()).rstrip()
trailer = b'Signed-off-by: %s <%s>' % (user_name, user_email)

def add_signed_off_by_trailer(commit, metadata):
  if trailer in commit.message:
    return

  # We want to add the trailer, but we want it to be separated from any
  # existing paragraphs by a blank line.  However, if the commit message
  # already ends with trailers, then we want all trailers to be on adjacent
  # lines.
  if not commit.message.endswith(b'\n'):
    commit.message += b'\n'
  lastline = commit.message.splitlines()[-1]
  if not re.match(b'[A-Za-z0-9-_]*: ', lastline):
    commit.message += b'\n'
  commit.message += trailer

# Setting source and target to anything prevents:
#   * remapping origin remote tracking branches to regular branches
#   * deletion of the origin remote
#   * nuking unused refs
#   * nuking reflogs
#   * repacking
# so we cheat and set source and target both to '.'
args = fr.FilteringOptions.parse_args(['--force',
                                       '--refs'] + myargs.rev_list_args)
args.refs = myargs.rev_list_args
filter = fr.RepoFilter(args, commit_callback=add_signed_off_by_trailer)
filter.run()
